home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / StaticTView.C < prev    next >
C/C++ Source or Header  |  1992-08-24  |  20KB  |  838 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "StaticTView.h"
  6.  
  7. #include "Class.h"
  8. #include "String.h"
  9. #include "View.h"
  10. #include "Window.h"
  11. #include "PrintManager.h"
  12. #include "TextFormatter.h"
  13. #include "TextPainter.h"
  14. #include "TextStyles.h"
  15. #include "CheapText.h"
  16. #include "Invariant.h"
  17. #include "Document.h"
  18. #include "Math.h"
  19.  
  20. Rectangle gFitRect(cFit, cFit);
  21.  
  22. void StaticTextView::SwapRange(int &a, int &b)
  23. {
  24.     int tmp;
  25.     tmp= a; a= b; b= tmp;
  26. }
  27.  
  28. inline LineMark *MarkAt(ObjArray *oa, int at)
  29. {
  30.     return (LineMark*)(*oa)[at]; 
  31. }
  32.  
  33. void StaticTextView::Dump()
  34. {
  35.     for(int i= 0; i < nLines; i++) {
  36.     if(MarkAtLine(i) == 0)
  37.         fprintf(stderr, "Mark is NULL at %d\n!!!", i);
  38.     else 
  39.         fprintf(stderr, "%d. %d-%d\n", i, StartLine(i), EndLine(i));
  40.     }
  41.     fprintf(stderr, "nLines= %d\n", nLines);
  42. }
  43.  
  44. void StaticTextView::ClassInvariant()
  45. {
  46.     if (GetAssertLevel() > 5)
  47.     return;
  48.     if(nLines > lines->Size()) 
  49.     fprintf(stderr, "!!!StaticTextView Invariant: nLines > lines->Size()!!!\n");
  50.     for(int i= 1; i < nLines; i++) {
  51.     if(MarkAtLine(i) == 0) {
  52.         fprintf(stderr, "!!!StaticTextView Invariant: Mark is NULL at %d!!!\n", i);
  53.         Dump();
  54.     }
  55.     else if(StartLine(i) == EndLine(i)) { 
  56.         fprintf(stderr, "!!!StaticTextView Invariant: Empty line at %d!!!\n", i);
  57.         Dump();
  58.     }
  59.     else if(StartLine(i) != EndLine(i-1)) {
  60.         fprintf(stderr, "!!!StaticTextView Invariant: Discontinous lines %d %d %d!!!\n", i, StartLine(i),
  61.                                    EndLine(i-1));
  62.         Dump();
  63.     }
  64.     }
  65. }
  66.     
  67. static TextPainter *sPainter;
  68. static TextFormatter *sFormatter;
  69. static CheapText *sText;
  70.  
  71. ONEXIT(StaticTextView)
  72. {
  73.     SafeDelete(sPainter);
  74.     SafeDelete(sFormatter);
  75.     SafeDelete(sText);
  76. }
  77.  
  78. //---- static methods ---------------------------------------------------------
  79.  
  80. Metric StaticTextView::MeasureText(char *text, Font* fd, int minwidth, int l)
  81.     if (l <= 1) {
  82.     if (minwidth > 0 || text == 0)
  83.         return Metric(minwidth, fd->Spacing(), fd->Ascender());
  84.     return Metric(fd->Width((byte*)text), fd->Spacing(), fd->Ascender());
  85.     }
  86.     return Metric(minwidth, l*fd->Spacing(), fd->Ascender());
  87. }
  88.  
  89. void StaticTextView::DrawBoxedText(Rectangle r, char *txt, 
  90.                         Font *fp, Ink *ink, bool wrap)
  91. {
  92.     Point p(r.origin);
  93.     p.y+= fp->Ascender();
  94.  
  95.     if (!wrap) {
  96.     Metric m(fp->Width((byte*)txt), fp->Spacing(), fp->Ascender());
  97.     if (m.extent.x > r.extent.x || m.extent.y > r.extent.y) {
  98.         GrState gs;
  99.         GrClipFurther(r);
  100.         GrShowString(fp, ink, p, (byte*)txt);
  101.     } else
  102.         GrShowString(fp, ink, p, (byte*)txt);
  103.     return;
  104.     }
  105.     
  106.     if (sPainter == 0) {
  107.     sPainter= new TextPainter;
  108.     sFormatter= new FoldingFormatter;
  109.     sText= new CheapText;
  110.     }
  111.     sText->ReplaceWithStr((byte*)txt);
  112.     sText->SetFont(fp);
  113.  
  114.     int nLines= sFormatter->Format(sText, sPainter, r.Width(), 0, sText->Size());
  115.     ObjArray *lines= sFormatter->GetLines();
  116.     
  117.     GrState gs;
  118.     GrClipFurther(r);
  119.     Ink *oldtextink= GrGetTextInk();
  120.     GrSetTextInk(ink);
  121.     register int i, lh, bh;
  122.     Rectangle lr(p.x, p.y-fp->Ascender(), p.x, MarkAt(lines, 0)->Height());
  123.     bh= MarkAt(lines, 0)->Base();
  124.     for (i= 0; i < nLines; i++) {
  125.     int start= MarkAt(lines, i)->Pos(), end= MarkAt(lines, i)->End();
  126.     sPainter->Draw(sText, p, start, end, lr, r, FALSE); 
  127.     p.y+= (lh= MarkAt(lines, i)->Height())-bh;
  128.     if (i < nLines-1)
  129.         p.y+= (bh= MarkAt(lines, i+1)->Base());
  130.     lr.origin.y+= lh; 
  131.     }        
  132.     GrSetTextInk(oldtextink);
  133. }
  134.  
  135. //----- StaticTextView Methods -------------------------------------------------
  136.  
  137. NewMetaImpl(StaticTextView, View, (TP(text), TP(pager), TP(painter), TP(formatter),
  138.     TE(align), TB(wrap), TB(drawViewBorder), TB(horExtend), T(border),
  139.     T(nLines), TP(lines), TP(marks)));
  140.  
  141. StaticTextView::StaticTextView(
  142.     EvtHandler *eh, Rectangle r, Text *t, 
  143.     bool w, TextViewFlags f, Point b, 
  144.     TViewAlign ta, int id
  145. ) : View(eh, r, id) 
  146. {
  147.     Init(r, t, w, f, b, ta);
  148. }   
  149.  
  150. void StaticTextView::Init(
  151.     Rectangle r, Text* t, bool w, TextViewFlags f, Point b, TViewAlign ta
  152. )
  153. {
  154.     lines= new ObjArray(32);
  155.     marks= new MarkList(FALSE, lines);
  156.     contentRect= r;
  157.     text= t;
  158.     align= ta;
  159.     wrap= w;
  160.     drawViewBorder= FALSE;
  161.     border= b;
  162.  
  163.     cline= 0;
  164.     cYPosition= 0;
  165.     
  166.     horExtend= (contentRect.extent.x == cFit);
  167.     if (horExtend)
  168.     wrap= FALSE;
  169.     
  170.     if (!wrap)
  171.     formatter= new SimpleFormatter();
  172.     else
  173.     formatter= new FoldingFormatter();
  174.     painter= new TextPainter();
  175.     
  176.     RepairAll();
  177.     
  178.     if ((f & eTextViewInvis) == eTextViewInvis)
  179.     SetFlag(eTextViewInvis);
  180.     if ((f & eTextViewReadOnly) == eTextViewReadOnly)
  181.     SetFlag(eTextViewReadOnly);
  182.     if ((f & eTextWantFindFocus) == eTextWantFindFocus)
  183.     SetFlag(eTextWantFindFocus);
  184.     if ((f & eTextViewNoBatch) == eTextViewNoBatch)
  185.     SetFlag(eTextViewNoBatch);
  186.     if ((f & eTextViewNoClip) == eTextViewNoClip)
  187.     SetFlag(eTextViewNoClip);
  188. }
  189.  
  190. StaticTextView::~StaticTextView()
  191. {
  192.     if (lines)
  193.     lines->FreeAll();
  194.     SafeDelete(marks);
  195.     SafeDelete(formatter);
  196.     SafeDelete(painter);
  197.     SafeDelete(pager);
  198. }
  199.  
  200. void StaticTextView::Draw(Rectangle r)
  201. {
  202.     register int i, lh, bh;
  203.     int startAt= PointToLine(r.origin-GetInnerOrigin());
  204.     Ink *oldtextink= 0; 
  205.  
  206.     if (startAt >= nLines)
  207.     return;
  208.       
  209.     GrState gs;
  210.     if (!TestFlag(eTextViewNoClip))
  211.     GrClipFurther(Rectangle(GetInnerOrigin(), GetInnerExtent()));
  212.     Point p= LineToPoint(startAt,TRUE) + GetInnerOrigin();
  213.     Rectangle lineRect(
  214.     GetInnerOrigin().x, p.y-BaseHeight(startAt),
  215.     GetInnerExtent().x, LineHeight(startAt)
  216.     );
  217.  
  218.     if (!Enabled()) {
  219.     oldtextink= GrGetTextInk();
  220.     GrSetTextInk(ePatGrey50);
  221.     }
  222.  
  223.     bh= BaseHeight(startAt);
  224.     for (i= startAt; ; i++) {
  225.     if (! r.Intersects(lineRect))
  226.         break;
  227.     DrawLine(p, i, lineRect, r);
  228.     if (i >= nLines-1)
  229.         break;
  230.     p.y+= (lh= LineHeight(i))-bh;
  231.     p.y+= (bh= BaseHeight(i+1));
  232.     lineRect.origin.y+= lh; 
  233.     }        
  234.     if (drawViewBorder) {
  235.     GrSetPenInk(ePatGrey50);
  236.     GrSetPenSize(2);
  237.     GrStrokeRect (Rectangle (contentRect.origin,contentRect.extent));
  238.     }
  239.     if (! Enabled())
  240.     GrSetTextInk(oldtextink);
  241. }
  242.  
  243. void StaticTextView::Repair(int from, int to, bool redraw)
  244. {
  245.     int prevBreak, nextBreak;
  246.     int prevLine, nextLine;
  247.     
  248.     ResetFlag(eTextViewModified);
  249.     prevBreak= text->FindLastBreak(from);
  250.     if(prevBreak < 0)
  251.     prevLine= -1;
  252.     else
  253.     prevLine= CharToLine(prevBreak);
  254.     prevLine= Math::Min(nLines-1, prevLine+1);
  255.     nextBreak= text->FindNextBreak(to);
  256.     if(nextBreak >= text->Size())
  257.     nextLine= nLines-1;
  258.     else
  259.     nextLine= CharToLine(nextBreak);
  260.     
  261.     int n= formatter->Format(
  262.     text, painter, GetInnerExtent().x,
  263.     prevBreak+1, nextBreak+1
  264.     );
  265.     ObjArray *newLines= formatter->GetLines();
  266.     
  267.     int extentDiff= UpdateView(prevLine, nextLine, n, newLines, redraw);
  268.     UpdateComposition(prevLine, nextLine, n, newLines);
  269.     UpdateExtent(extentDiff);
  270.     if (pager)
  271.     pager->Repaginate(prevLine);
  272. //    ClassInvariant();
  273. }
  274.  
  275. Rectangle StaticTextView::NextPageBreak(int pn, Rectangle r)
  276. {
  277.     if (pager == 0)
  278.     pager= new TextPager();
  279.     return pager->NextPageBreak(pn, r, this);
  280. }
  281.  
  282. int StaticTextView::UpdateView(
  283.     int prev, int next, int n, ObjArray *newLines, bool redraw
  284. {
  285.     int i, j;
  286.     int invalid, valid;
  287.     
  288.     int newHeight= 0, oldHeight= 0;
  289.     for(i= 0; i < n; i++)
  290.     newHeight+= MarkAt(newLines, i)->Height();
  291.     for(i= prev; i <= next; i++)
  292.     oldHeight+= MarkAtLine(i)->Height();
  293.     
  294.     if(redraw) {
  295.     invalid= prev;
  296.     valid= cMaxInt;
  297.     } else {    
  298.     invalid= prev;
  299.     for(i= prev; i < prev+n && i <= next; i++) {
  300.         if(MarkAt(newLines, i-prev)->IsDifferent(MarkAtLine(i))) 
  301.         break;
  302.     }
  303.     invalid= i;
  304.         
  305.     valid= nLines;
  306.     if (oldHeight == newHeight) {
  307.         for(j= prev+n-1; j > invalid && j < nLines; j--) {
  308.         if(!MarkAt(newLines, j-prev)->IsDifferent(MarkAtLine(j))) 
  309.             valid= j;
  310.         else
  311.             break;
  312.         }               
  313.         if(valid == nLines)
  314.         valid= Math::Min(nLines, prev+n);
  315.         InvalidateRange(invalid, Math::Max(0, valid-1)); //
  316.     }
  317.     else 
  318.            InvalidateRange(invalid, Math::Max(0, valid-1));
  319.     }
  320.     InvalidateRange(invalid, Math::Max(0, valid-1));
  321.     //---- update line cache
  322.     LineToPoint(Math::Max(0, invalid-1));
  323.     return newHeight-oldHeight;
  324. }
  325.     
  326. void StaticTextView::UpdateComposition(
  327.     int prev, int next, int n, ObjArray *newLines
  328. {
  329.     int diff= n-(next-prev+1);
  330.     register int i;
  331.     
  332.     if(lines->Size() < nLines+diff)
  333.     lines->Expand((nLines+diff)*2);
  334.     if(diff > 0) {
  335.     for(i= nLines-1; i > next; i--)
  336.         lines->AtPut(i+diff, lines->At(i));
  337.     for(i= next+1; i <= next+diff; i++)
  338.         lines->AtPut(i, 0);
  339.     } else if (diff < 0) {
  340.     for(i= next+diff+1; i <= next; i++) {
  341.         LineMark *lm= MarkAtLine(i);
  342.         SafeDelete(lm);
  343.     }
  344.     for(i= next+1; i < nLines; i++)
  345.         lines->AtPut(i+diff, MarkAtLine(i));
  346.     for(i= nLines+diff; i < nLines; i++)
  347.         lines->AtPut(i, 0);    
  348.     }
  349.     
  350.     for(i= prev; i < prev+n; i++) {
  351.     LineMark *m1= MarkAtLine(i);
  352.     if(m1 == 0)
  353.         m1= new LineMark();
  354.     m1->Copy(MarkAt(newLines, i-prev));
  355.     lines->AtPut(i, m1);
  356.     }    
  357.     nLines+= diff;
  358. }
  359.  
  360. void StaticTextView::DrawLine(Point p, int i, Rectangle lr, Rectangle cr)
  361. {
  362.     int start= StartLine(i), end= EndLine(i);
  363.     painter->Draw(text, p, start, end, lr, cr, TestFlag(eTextViewInvis)); 
  364. }
  365.  
  366. void StaticTextView::SetFont(Font* fd)
  367. {
  368.     text->SetFont(fd);
  369.     RepairAll();
  370. }
  371.  
  372. void StaticTextView::SetFormatter(TextFormatter *f)
  373. {
  374.     SafeDelete(formatter);
  375.     formatter= f;
  376. }
  377.  
  378. void StaticTextView::SetPainter(TextPainter *p)
  379. {
  380.     SafeDelete(painter);
  381.     painter= p;
  382. }
  383.  
  384. void StaticTextView::SetPager(TextPager *p)
  385. {
  386.     SafeDelete(pager);
  387.     pager= p;
  388. }
  389.  
  390. void StaticTextView::SetAlign(TViewAlign m)
  391. {
  392.     align= m;
  393.     RepairAll();
  394. }
  395.  
  396. void StaticTextView::ShowInvisibles(bool m)
  397. {
  398.     if (TestFlag(eTextViewInvis) != m) {
  399.         SetFlag(eTextViewInvis, m);
  400.         ForceRedraw();
  401.     }
  402. }
  403.  
  404. bool StaticTextView::GetShowInvis()
  405.     return TestFlag(eTextViewInvis); 
  406. }
  407.  
  408. void StaticTextView::SetWordWrap(bool m)
  409.     if (wrap == m)
  410.     return;
  411.     wrap= m;
  412.     SafeDelete(formatter);
  413.     if (wrap)
  414.     formatter= new FoldingFormatter(); 
  415.     else
  416.     formatter= new SimpleFormatter(); 
  417.     RepairAll();
  418. }
  419.  
  420. bool StaticTextView::GetWordWrap()
  421.     return wrap; 
  422. }
  423.  
  424. void StaticTextView::SetNoBatch(bool m)
  425. {
  426.     SetFlag(eTextViewNoBatch, m);
  427. }
  428.  
  429. bool StaticTextView::GetNoBatch()
  430.     return TestFlag(eTextViewNoBatch); 
  431. }
  432.  
  433. Text *StaticTextView::SetText(Text *t, bool scroll)
  434. {
  435.     Text *old= text;
  436.     text= t;   
  437.     SetFlag(eTextViewModified);
  438.     RepairAll();  
  439.     if (scroll == cRevealTop)
  440.     Scroll(cPartScrollAbs, gPoint0, FALSE);
  441.     Send(GetId(), cPartReplacedText, 0);
  442.     return old;
  443. }
  444.  
  445. void StaticTextView::SetString(byte *str, int len)
  446. {
  447.     text->ReplaceWithStr(str, len);
  448.     RepairAll();
  449.     Send(GetId(), cPartReplacedText, 0);  
  450. }
  451.  
  452. void StaticTextView::RepairAll()
  453. {
  454.     // flush line cache
  455.     LineToPoint(0);
  456.     nLines= 1;
  457.     contentRect.extent.y= 2*border.y;
  458.     LineMark *m= MarkAtLine(0);
  459.     if (m == 0) {
  460.     m= new LineMark();
  461.     lines->AtPut(0, m);
  462.     }
  463.     m->ChangeMark(0, text->Size(), LineDesc(), eStateChanged);
  464.     Repair(0, text->Size(), TRUE);
  465.     ForceRedraw();
  466. }
  467.  
  468. void StaticTextView::SetExtent(Point p)
  469. {
  470.     if (p != contentRect.extent) {
  471.     View::SetExtent(p);
  472.     horExtend= (p.x == cFit);
  473.     if (horExtend)
  474.         wrap= FALSE;
  475.     SafeDelete(formatter);
  476.     if (!wrap)
  477.         formatter= new SimpleFormatter();
  478.     else
  479.         formatter= new FoldingFormatter();
  480.     RepairAll();
  481.     }
  482. }
  483.  
  484. Metric StaticTextView::GetMinSize()
  485. {
  486.     if (TestFlag(eTextViewModified))
  487.     RepairAll();
  488.     return Metric(GetExtent(), LineToPoint(0, TRUE).y+border.y);
  489. }
  490.  
  491. void StaticTextView::UpdateExtent(int dy)
  492. {
  493.     Point newExtent(contentRect.extent);
  494.     Point newOrigin(contentRect.origin);
  495.     register int i, s, e;
  496.  
  497.     newExtent.y+= dy;
  498.  
  499.     if (horExtend) {
  500.     newExtent.x= 0;
  501.     for (i= 0; i < nLines; i++) {
  502.         s= StartLine(i);
  503.         e= EndLine(i);
  504.         newExtent.x= Math::Max(newExtent.x, painter->LineWidth(text, s, e));
  505.     }
  506.     newExtent.x += 2*border.x;
  507.     if (align != eTViewLeft) 
  508.         newOrigin.x= AlignView(newExtent.x);
  509.     }
  510.  
  511.     InvalidateDiff(newOrigin, newExtent);
  512.     
  513.     if (newOrigin != contentRect.origin) 
  514.     View::SetOrigin(newOrigin);
  515.     if (newExtent != contentRect.extent) 
  516.     View::SetExtent(newExtent);
  517. }
  518.  
  519. void StaticTextView::InvalidateDiff(Point newOrigin, Point newExtent)
  520. {
  521.     if (newExtent != contentRect.extent) {
  522.     Rectangle r[4];
  523.     Rectangle oldRect(contentRect);
  524.     oldRect.Expand(Point(4, 0));
  525.     Rectangle newRect(newOrigin, newExtent);
  526.     newRect.Expand(Point(4, 0));
  527.     int n= Difference(r, newRect, oldRect);
  528.     for (int i= 0; i < n; i++)
  529.         InvalidateRect(r[i]);
  530.     }   
  531. }
  532.  
  533. Point StaticTextView::LineToPoint(int n, bool basePoint, bool relative)
  534. {
  535.     register i, y= cYPosition;
  536.     
  537. //  int _cYPos, _cline;
  538. //  _cYPos= cYPosition; _cline= cline; 
  539.     n= Math::Range(0, nLines, n);
  540.     if (cline < n) 
  541.     for(i= cline; i < n; i++)
  542.         y+= LineHeight(i);
  543.     else if (cline > n) 
  544.     for(i= cline-1; i >= n; i--)
  545.         y-= LineHeight(i);
  546.     cYPosition= y;
  547.     cline= n;
  548.     
  549. //    int yy= 0;
  550. //    for (int ii= 0; ii < n; ii++)
  551. //        yy+= LineHeight(ii);
  552. //    if (cYPosition != yy)
  553. //        fprintf(stderr, "LineToPoint: cYPosition %d!= %d, p=%d l=%d\n", 
  554. //            cline, n, _cYPos, _cline); 
  555.  
  556.     if (basePoint)
  557.     y+= BaseHeight(n);
  558.     if (relative)
  559.     return Point(0, y);
  560.     return GetInnerOrigin() + Point(0, y);
  561. }
  562.  
  563. int StaticTextView::PointToLine(Point p) // p is in coordinates relative to contentRect
  564. {
  565.     int i, py= Math::Range(0, contentRect.Height(), p.y), lh;
  566.  
  567. //    int _py, _cYPos, _cline;
  568. //    _py= py; _cYPos= cYPosition; _cline= cline; 
  569.     if(py >= cYPosition) {
  570.     for(i= cline; i < nLines; i++) {
  571.         lh= LineHeight(i);
  572.         if (cYPosition + lh > py)
  573.         break;
  574.         cYPosition+= lh;
  575.     }
  576.     cline= i;
  577.     } else {
  578.     for(i= cline-1; i >= 0 ; i--) {
  579.         cYPosition-= LineHeight(i);
  580.         if (cYPosition <= py) 
  581.         break;
  582.     }
  583.     cline= Math::Max(i, 0);
  584.     }
  585.     
  586. //    register int ll, y2= 0;
  587. //    for (ll= 0; ll < nLines; ll++) {
  588. //        lh= LineHeight(ll);
  589. //        if (y2 + lh > py)
  590. //            break;
  591. //        y2+= lh;
  592. //    }
  593. //    if (ll != cline) 
  594. //        fprintf(stderr, "PointToLine: cline %d!= %d, p=%d y=%d l=%d\n", 
  595. //            cline, ll, _py, _cYPos, _cline); 
  596.     return cline; 
  597. }
  598.  
  599. //---- map a point in view coordinates to line and character number
  600.  
  601. void StaticTextView::PointToPoint(
  602.     Point p, Point *viewPos, int *lineNo, int *charNo, bool relative
  603. )
  604. {
  605.     int start, end, cx= 0, l; 
  606.     if (!relative)
  607.         p-= GetInnerOrigin();
  608.     l= PointToLine(p);
  609.     if (l >= nLines) {
  610.     l= nLines-1;
  611.     p.x= contentRect.extent.x;    // set to end of line
  612.     }
  613.     if (l < 0) {
  614.     l= 0;
  615.     p.x= contentRect.origin.x;            // set to start of line
  616.     }
  617.     start= StartLine(l);
  618.     end= EndLine(l);
  619.  
  620.     *charNo= painter->Map(text, start, end, end, p.x, GetInnerExtent().x, &cx);
  621.     *lineNo= l;
  622.     *viewPos= Point(cx, LineToPoint(l).y);
  623.     if (!relative)
  624.         (*viewPos) += GetInnerOrigin();
  625. }
  626.  
  627. int StaticTextView::CharToLine(int ch)
  628. {
  629.     register int base, pos, last, s;
  630.     
  631.     base= pos= 0;
  632.     last= nLines-1;
  633.     
  634.     while (last >= base) { // binary search
  635.     pos= (base+last) / 2;
  636.     if (EndLine(pos) > ch && (s= StartLine(pos)) <= ch)
  637.         break;
  638.     if (StartLine(pos) > ch)
  639.         last= pos-1;
  640.     else
  641.         base= pos+1;
  642.     }
  643.     return Math::Max(0, Math::Min(pos, nLines-1));
  644. }
  645.  
  646. int StaticTextView::CharToPoint(int charNo, int *lineNo, Point *viewPos, bool relative)
  647. {
  648.     int line, ch, start, end, x;
  649.     Point p;
  650.  
  651.     ch= Math::Range(0, text->Size(), charNo);
  652.     line= CharToLine(ch);
  653.     p.y= LineToPoint(line).y;
  654.     if (line >= nLines && line > 0) { // beyound end of text
  655.     p.y-= LineHeight(line);
  656.     line= Math::Max(0,nLines-1);
  657.     }
  658.     start= StartLine(line);
  659.     end= EndLine(line);
  660.  
  661.     ch= painter->Map(text, start, end, charNo, cMaxInt, GetInnerExtent().x, &x); 
  662.     *viewPos= p;
  663.     viewPos->x+= x;
  664.     if (!relative)
  665.     *viewPos += GetInnerOrigin();
  666.     *lineNo= line;
  667.     return ch;
  668. }
  669.  
  670. int StaticTextView::LineHeight(int l)
  671. {
  672.     l= Math::Range(0, nLines-1, l);
  673.     return MarkAtLine(l)->Height();
  674. }
  675.     
  676. int StaticTextView::BaseHeight(int l)
  677. {
  678.     l= Math::Range(0, nLines-1, l);
  679.     return MarkAtLine(l)->Base();
  680. }
  681.  
  682. void StaticTextView::InvalidateRange(int from, int to)
  683. {
  684.     if (from > to)  // normalize range
  685.     SwapRange(from, to);
  686.     from= Math::Range(0, nLines-1, from);
  687.     to=   Math::Range(0, nLines-1, to);
  688.     Point p= LineToPoint(from),
  689.       t= Point(contentRect.extent.x, LineToPoint(to).y+LineHeight(to));
  690.     Rectangle r= NormRect(p, t);
  691.  
  692.     r += GetInnerOrigin();
  693.     if (from == 0)  { // consider border
  694.     r.origin.y -= border.y;
  695.     r.extent.y += border.y;
  696.     }
  697.     if (to == nLines-1 || to == 0) 
  698.     r.extent.y += border.y;
  699.     InvalidateRect(r.Expand(Point(Math::Max(4,border.x),0)));
  700. }
  701.  
  702. int StaticTextView::AlignView(int newX)
  703. {
  704.     int x;
  705.     // adjust origin
  706.     switch (align) {
  707.     case eTViewCenter:
  708.     x= contentRect.origin.x + 
  709.               (contentRect.extent.x-newX)/2;
  710.     break;
  711.     case eTViewRight:
  712.     x= contentRect.origin.x + 
  713.               (contentRect.extent.x-newX);
  714.     break;
  715.     }
  716.     return x;
  717. }
  718.  
  719. void StaticTextView::InvalidateRange(int from, Point fp, int to, Point tp)
  720. {
  721.     Rectangle r;
  722.  
  723.     from= Math::Range(0, nLines-1, from);
  724.     to=   Math::Range(0, nLines-1, to);
  725.  
  726.     if ((from == to && fp.x > tp.x) || from > to) { // normalize range
  727.     SwapRange(from, to);
  728.     Swap(fp, tp);   
  729.     }
  730.  
  731.     if (from == to) { // optimize invalidate on one line
  732.     r= Rectangle(LineToPoint(from)+Point (fp.x,0),
  733.                     Point(tp.x-fp.x, LineHeight(from)));
  734.     if (from == 0)  { // consider border
  735.         r.origin.y -= border.y;
  736.         r.extent.y += border.y;
  737.     }
  738.     if (to == nLines-1 || to == 0) 
  739.         r.extent.y += border.y;
  740.     r.origin+= GetInnerOrigin();
  741.     InvalidateRect(r.Expand(Point(Math::Max(4,border.x),0)));
  742.     return;
  743.     }
  744.     InvalidateRange(from, to);
  745. }
  746.  
  747. char *StaticTextView::AsString()
  748. {
  749.     return text->AsString();
  750. }
  751.  
  752. OStream& StaticTextView::PrintOn (OStream&s)
  753. {
  754.     View::PrintOn(s);
  755.     return s << text SP << wrap SP << align SP 
  756.          << horExtend SP << border SP << contentRect.extent;
  757. }
  758.  
  759. IStream& StaticTextView::ReadFrom(IStream &s)
  760. {
  761.     Text *txt;
  762.     bool wrap, hExtend;
  763.     Point extent, itsBorder;
  764.     TViewAlign align;
  765.     Rectangle r;
  766.  
  767.     SafeDelete(text);
  768.  
  769.     View::ReadFrom(s);
  770.     s >> txt >> Bool(wrap) >> Enum(align) 
  771.       >> Bool(hExtend) >> itsBorder >> extent;
  772.     r= Rectangle(extent);
  773.     if (hExtend)
  774.     r.extent.x= cFit;
  775.  
  776.     Init(r, txt, wrap, eTextViewNone, itsBorder, align);
  777.     return s;
  778. }
  779.  
  780. void StaticTextView::AddMark(Mark *m)
  781. {
  782.     text->AddMark(m);
  783. }
  784.  
  785. Mark *StaticTextView::RemoveMark(Mark *m)
  786. {
  787.     return text->RemoveMark(m);
  788. }
  789.  
  790. Iterator *StaticTextView::GetMarkIter()
  791. {
  792.     return text->GetMarkIter();
  793. }
  794.  
  795. MarkList *StaticTextView::GetMarkList()
  796. {
  797.     return text->GetMarkList();
  798. }
  799.  
  800. void StaticTextView::InspectorId(char *buf, int sz)
  801. {
  802.     if (text)
  803.     text->InspectorId(buf, sz);
  804.     else
  805.     View::InspectorId(buf, sz);
  806. }
  807.  
  808. void StaticTextView::CollectParts(Collection* col)
  809. {
  810.     View::CollectParts(col);
  811.     col->Add(text);
  812. }
  813.  
  814. void StaticTextView::PrintAdorn(Rectangle, int gPageNo)
  815. {
  816.     Rectangle r(gPrintManager->GetViewRect());
  817.     Point o;
  818.     byte *p;
  819.     Font *f= new_Font(eFontTimes, 12, eFaceBold);
  820.     r.origin.y-= 10;
  821.  
  822.     p= (byte*) GetDocument()->GetBaseName();
  823.     o= f->AdjustString(p, r.NW(), eAdjVBottom, eAdjHLeft);
  824.     GrShowString(f, gInkBlack, o, p);
  825.  
  826.     p= (byte*) form("Page: %d", gPageNo);
  827.     o= f->AdjustString(p, r.NE(), eAdjVBottom, eAdjHRight);
  828.     GrShowString(f, gInkBlack, o, p);
  829. }
  830.     
  831.